package org.ctstudio.common.security.digest;

import org.ctstudio.common.utils.Base64Util;
import org.ctstudio.common.utils.ByteUtil;

import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class DigestAlgorithm {
  public static final String MD5 = "MD5";
  public static final String SHA1 = "SHA-1";
  public static final String SHA256 = "SHA-256";

  /**
   * MD5的算法在RFC1321 中定义 在RFC 1321中，给出了Test suite用来检验你的实现是否正确： MD5 ("") =
   * d41d8cd98f00b204e9800998ecf8427e MD5 ("a") =
   * 0cc175b9c0f1b6a831c399e269772661 MD5 ("abc") =
   * 900150983cd24fb0d6963f7d28e17f72 MD5 ("message digest") =
   * f96b697d7cb7938d525a2f31aaf161d0 MD5 ("abcdefghijklmnopqrstuvwxyz") =
   * c3fcd3d76192e4007dfb496cca67e13b
   * 
   * @throws NoSuchAlgorithmException
   **/
  public static DigestAlgorithm getMD5() throws NoSuchAlgorithmException {
    return getInstance(MD5);
  }

  public static DigestAlgorithm getSHA1() throws NoSuchAlgorithmException {
    return getInstance(SHA1);
  }

  public static DigestAlgorithm getSHA256() throws NoSuchAlgorithmException {
    return getInstance(SHA256);
  }

  protected static DigestAlgorithm getInstance(String cyptorName) throws NoSuchAlgorithmException {
    return new DigestAlgorithm(cyptorName);
  }

  private MessageDigest md;

  protected DigestAlgorithm(String cyptorName) throws NoSuchAlgorithmException {
    this.md = MessageDigest.getInstance(cyptorName);
  }

  public byte[] digest(InputStream before) throws IOException {
    byte[] dataBytes = new byte[1024];
    int nread = 0;
    while ((nread = before.read(dataBytes)) != -1) {
      md.update(dataBytes, 0, nread);
    }
    byte[] mdbytes = md.digest();
    return mdbytes;
  }

  public String digestHexLowercase(InputStream before) throws IOException {
    byte[] mdbytes = digest(before);
    return ByteUtil.getInstance().bytes2HexLowercase(mdbytes);
  }

  public String digestHexUppercase(InputStream before) throws IOException {
    byte[] mdbytes = digest(before);
    return ByteUtil.getInstance().bytes2HexUppercase(mdbytes);
  }

  public byte[] digest(byte[] before) {
    return md.digest(before);
  }

  public byte[] digest(String before) {
    return digest(before.getBytes());
  }

  public String digestBase64(byte[] before) {
    return Base64Util.getInstance().toBase64(digest(before));
  }

  public String digestBase64(String before) {
    return Base64Util.getInstance().toBase64(digest(before));
  }

  public String digestHexLowercase(byte[] before) {
    byte[] mdbytes = digest(before);
    return ByteUtil.getInstance().bytes2HexLowercase(mdbytes);
  }

  public String digestHexLowercase(String before) {
    return digestHexLowercase(before.getBytes());
  }

  public String digestHexUppercase(byte[] before) {
    byte[] mdbytes = digest(before);
    return ByteUtil.getInstance().bytes2HexUppercase(mdbytes);
  }

  public String digestHexUppercase(String before) {
    return digestHexUppercase(before.getBytes());
  }

  public void update(byte[] input, int offset, int len) {
    md.update(input, offset, len);
  }

  public void update(byte input) {
    md.update(input);
  }

  public byte[] digest() {
    return md.digest();
  }

  public String digestBase64() {
    return Base64Util.getInstance().toBase64(digest());
  }

  public String digestHexLowercase() {
    byte[] mdbytes = digest();
    return ByteUtil.getInstance().bytes2HexLowercase(mdbytes);
  }

  public String digestHexUppercase() {
    byte[] mdbytes = digest();
    return ByteUtil.getInstance().bytes2HexUppercase(mdbytes);
  }

}
